
#include "IO.h"
#include "BSP_Config.h"

#include "FreeRTOS.h"
#include "Task.h"
#include "semphr.h"

static xSemaphoreHandle mutex[2];

typedef struct SPI {
	uint32_t spi;
	rcu_periph_enum rcu;
	IO_T nss;
	AFIO_T sck;
	AFIO_T miso;
	AFIO_T mosi;
}SPI_T;

static const SPI_T spis [] = {
	[0] = {
		.spi = SPI0,
		.rcu = RCU_SPI0,
		.nss = IO_INIT_TABLE(GPIOA, GPIO_PIN_12),
		.sck = AFIO_INIT(GPIOA, GPIO_PIN_11, GPIO_AF_0),
		.miso = AFIO_INIT(GPIOA, GPIO_PIN_10, GPIO_AF_0),
		.mosi = AFIO_INIT(GPIOA, GPIO_PIN_9, GPIO_AF_0),
	},
	
#if 0
	[1] = {
		.spi = SPI1,
		.rcu = RCU_SPI1,
		.nss = IO_INIT_TABLE(GPIOA, GPIO_PIN_15),
		.sck = IO_INIT_TABLE(GPIOB, GPIO_PIN_13),
		.miso = IO_INIT_TABLE(GPIOB, GPIO_PIN_14),
		.mosi = IO_INIT_TABLE(GPIOB, GPIO_PIN_15),
	},
#endif 
	
#if 0
	[2] = {
		.spi = SPI2,
		.rcu = RCU_SPI2,
		.nss = IO_INIT_TABLE(GPIOA, GPIO_PIN_15),
		.sck = IO_INIT_TABLE(GPIOB, GPIO_PIN_3),
		.miso = IO_INIT_TABLE(GPIOB, GPIO_PIN_4),
		.mosi = IO_INIT_TABLE(GPIOB, GPIO_PIN_5),
	},
#endif 

};

//从SCK频率计算分频系数（PSC）
static uint32_t BSP_SPI_ClkToPsc(uint32_t spi, uint32_t clk){
	uint32_t freq = rcu_clock_freq_get((spi == SPI0) ? CK_APB2 : CK_APB1);
	uint32_t div = freq * 10 / clk;
	
	if(div <= 20) 
		return SPI_PSC_2;
	if(div <= 40) 
		return SPI_PSC_4;
	if(div <= 80) 
		return SPI_PSC_8;
	if(div <= 160) 
		return SPI_PSC_16;
	if(div <= 320) 
		return SPI_PSC_32;
	if(div <= 640) 
		return SPI_PSC_64;
	if(div <= 1280) 
		return SPI_PSC_128;

	return SPI_PSC_256;
}

static void BSP_SPI_Config(const SPI_T* spi, uint32_t freq)
{
    spi_parameter_struct spi_init_struct;
	uint32_t psc = BSP_SPI_ClkToPsc(spi->spi, freq);
	
    rcu_periph_clock_enable(spi->rcu);
	
    spi_i2s_deinit(spi->spi);

    spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;
    spi_init_struct.device_mode          = SPI_MASTER;
    spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
    spi_init_struct.nss                  = SPI_NSS_SOFT;
    spi_init_struct.prescale             = psc;
    spi_init_struct.endian               = SPI_ENDIAN_MSB;
    spi_init(spi->spi, &spi_init_struct);
    
    spi_nss_internal_high(spi->spi);
    spi_enable(spi->spi);
}

static void BSP_SPI_GPIO_Init(const SPI_T* spi){
	AFIO_Init(&spi->sck);
	AFIO_Init(&spi->mosi);
	AFIO_Init(&spi->miso);
	
	IO_Init(&spi->nss, IO_Mode_OUT);
	IO_Set(&spi->nss, 1);
}


void BSP_SPI_Init(uint8_t id, uint32_t freq){
	BSP_SPI_GPIO_Init(&spis[id]);
	BSP_SPI_Config(&spis[id], freq);
//		mutex[id] = xSemaphoreCreateRecursiveMutex();
}

uint8_t BSP_SPI_Exchange(uint8_t id, uint8_t TxByte){
	uint32_t spi = spis[id].spi;
	while(RESET == spi_i2s_flag_get(spi, SPI_FLAG_TBE)){;}
	spi_i2s_data_transmit(spi, TxByte);
	while(RESET == spi_i2s_flag_get(spi, SPI_FLAG_RBNE)){;}
	return (uint8_t)spi_i2s_data_receive(spi);
}

void BSP_SPI_SetNSS(uint8_t id, uint8_t state){
	IO_Set(&spis[id].nss, state);
}

#if 0
ErrStatus BSP_SPI_MutexTake(uint8_t id, TickType_t xTicksToWait)
{
	if(mutex[id] == NULL)return ERROR;
	if(xSemaphoreTakeRecursive(mutex[id], xTicksToWait) == pdTRUE)
		return SUCCESS;
	else 
		return ERROR;
}

void BSP_SPI_MutexGive(uint8_t id)
{
	xSemaphoreGiveRecursive(mutex[id]);
}
#endif 

